<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>5命令模式</title>
</head>

<body>

  <h1>(将行为函数包装成对象方法)然后我们要先把这些行为都封装在命令类中： <h1>

      <p>
        有时候需要向某些对象发送请求，但是并不知道请求的接收者是谁，也不知道被请
        求的操作是什么，此时希望用一种松耦合的方式来设计软件，使得请求发送者和请求接 收者能够消除彼此之间的耦合关系。
      </p>

      <p>
        命令模式的由来，其实是回调（callback）函数的一个面向对象的替代品。
      </p>

      <p>
        跟许多其他语言不同，JavaScript 可以用高阶函数非常方便地实 现命令模式。命令模式在 JavaScript 语言中是一种隐形的模式。
        命令栈 记录上一次命令执行的结果用栈的结构来实现,每次执行命令后往栈中最后增加数据
      </p>

      <p>
        撤消和重做可以利用一个历史列表堆栈办到。记录命令日志，然后重复执行它们，

      </p>

      <button id="btn1">刷新</button>
      <button id="btn2">增加</button>
      <button id="btn3">删除</button>

      <script>
        // 行为对象
        const MenuBar = {
          refresh: function () {
            console.log('刷新菜单界面');
          }
        };

        // 命令类 (用于安装命令)
        const RefreshMenuBarCommand = function (receiver) {
          return {
            execute() {
              receiver.refresh();
            }
          }
        };

        // 设置命令
        const setCommand = function (button, command) {
          button.onclick = function () {
            command.execute();
          }
        };

        const refreshMenuBarCommand = RefreshMenuBarCommand(MenuBar);

        setCommand(button1, refreshMenuBarCommand);



        // =============
        const btn1 = document.getElementById('btn1')
        const btn2 = document.getElementById('btn2')
        const btn3 = document.getElementById('btn3')

        // 安装命令函数
        function setCommand(btn, command) {
          btn.addEventListener('click', () => {
            command.execute()
          })
        }

        // 定义功能
        const menuBar = {
          refresh() {
            console.log('刷新菜单')
          }
        }

        const subMenu = {
          add() {
            console.log('增加菜单')
          },
          del() {
            console.log('删除菜单')
          }
        }

        // 封装命令类
        class RefreshMenuBarCommand {
          constructor(receiver) {
            this.receiver = receiver
          }
          execute() {
            this.receiver.refresh()
          }
        }

        class AddSubMenuCommand {
          constructor(receiver) {
            this.receiver = receiver
          }
          execute() {
            this.receiver.add()
          }
        }

        class DelSubMenuCommand {
          constructor(receiver) {
            this.receiver = receiver
          }
          execute() {
            this.receiver.del()
          }
        }

        // 安装命令
        const refreshMenuBarCommand = new RefreshMenuBarCommand(menuBar)
        const addSubCommand = new AddSubMenuCommand(subMenu)
        const delSubMenuCommand = new DelSubMenuCommand(subMenu)

        setCommand(btn1, refreshMenuBarCommand)
        setCommand(btn2, addSubCommand)
        setCommand(btn3, delSubMenuCommand)

      </script>
</body>

</html>